#!/usr/bin/perl
use warnings ;
use strict ;

use LWP::UserAgent ;
use JSON ;
use JSON::Parse 'valid_json';
use Term::ReadKey ;

use Getopt::Long ;

use Carp::Assert ;
use Data::Dumper ;

use Time::HiRes qw( usleep ualarm gettimeofday tv_interval nanosleep
                  clock_gettime clock_getres clock_nanosleep clock
                  stat );

my $Debug = '';
my $IPWithPort = '192.168.20.6:55556';
my $TmpKey ;
my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my @weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
my $CSV_FileName ;
my $CSV_FileHandle ;
my $CSVFileStr ;

my $OptionRetVal = GetOptions (	'debug' => \$Debug, 'ip' => \$IPWithPort );

my $JSON = JSON->new->allow_nonref ;
my $UA = LWP::UserAgent->new();
$UA->timeout(1);

my @TrackedIndicesArray ;

while (1) {

	&ClearScreen ();
	print "\nSensorMonHTTP Web Server Sensor Recorder Command Center\n" ;
	print "\nCurrently Active IP : $IPWithPort\n" ;
	print "\nMenu:\n" ;
	print "\n1. Change SensorMonHTTP Server IP" ;
	print "\n2. Check and Select Available Sensor Parameters" ;
	print "\n3. Sensor Logging Options" ;
	print "\n4. Exit Command Center" ;
	print "\n\nEnter choice: " ;

	my $Option = <STDIN> ;
	chomp $Option ;

	assert ( ($Option >= 1 && $Option <= 4), 'Selected Option Unavailable' ) ;

	if ($Option == 1) {

		print "\nCurrent SensorMonHTTP Server: $IPWithPort\n" ;
		print "\nChoose New SensorMonHTTP Server: " ;
		$IPWithPort = <STDIN> ;
		chomp $IPWithPort ;

	} elsif ($Option == 2) {

		my $CurrPage = "http://" . $IPWithPort ;
		my $GetResponse0 ;
		my $DevStatusJSON ;
		do {
			$GetResponse0 = $UA->get ($CurrPage) ;
		} while !($GetResponse0->is_success) ;
		$DevStatusJSON = $GetResponse0->decoded_content ;
		my $JSONText = $JSON->decode ($DevStatusJSON) ;

		for my $Idx0 (0..scalar @{$JSONText} - 1) {
			my $SensorDetailsHashRef = $JSONText->[$Idx0] ;
			my $SensorName = $SensorDetailsHashRef->{'SensorName'} ;
			print "\n$SensorName : Record? (Y/N) ";
			$TmpKey = <> ;
			chomp $TmpKey ;
			if ($TmpKey =~ m/Y/ || $TmpKey =~ m/y/) {
				push (@TrackedIndicesArray, $Idx0);
			}
		}

		print "\nPress any key to get back to main menu... " ;
		$TmpKey = <> ;

	} elsif ($Option == 3) {

		if (scalar @TrackedIndicesArray == 0) {

			print "\nNo parameters selected for recording. Please utilize Option 2 first...\n " ;
			$TmpKey = <> ;

		} else {

			print "\nPress (P - Start Logging to CSV File, Q - Stop Logging)\n" ;
			my $WaitForInputs = 1 ;
			while ($WaitForInputs == 1) {

				ReadMode ('cbreak');
 				my $KeyPress ;
 				while (not defined ($KeyPress = ReadKey(-1))) {
 				} 
				my $WriteToCSVFile = ($KeyPress eq "P" || $KeyPress eq "p") ? 1 : 0 ;

 				if ($WriteToCSVFile == 1) {
						
					my $SampleStartTime = [gettimeofday] ;
			 		my ($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
			 		my $year = 1900 + $yearOffset;
			 		my $theTime = "$hour-$minute-$second-$weekDays[$dayOfWeek]-$months[$month]-$dayOfMonth-$year" ;
					my $CurrPage = "http://" . $IPWithPort ;		
					my $GetResponse0 ;
					my $DevStatusJSON ;

			 		# Open the file
			 		my $SocketString = "SensorMonHTTP" ;
					my $IP = $IPWithPort ;
					$IP =~ s/:.*//g ;
			 		$CSV_FileName = sprintf "%s-%s-%s.csv", $SocketString, $IP, $theTime ;
			 		printf "\n\nStarted recording sensor data from %s to %s\n\n", $IPWithPort, $CSV_FileName ;
					my $CSVFileStr = "" ;
					do {
						$GetResponse0 = $UA->get ($CurrPage) ;
					} while !($GetResponse0->is_success) ;
					$DevStatusJSON = $GetResponse0->decoded_content ;
					my $JSONText = $JSON->decode ($DevStatusJSON) ;

					$CSVFileStr .= "Time" ;
					for my $TmpIdx (0 .. scalar @TrackedIndicesArray - 1) {
						my $JSONIdx = $TrackedIndicesArray[$TmpIdx] ;
						my $SensorDetailsHashRef = $JSONText->[$JSONIdx];
						my $SensorName = $SensorDetailsHashRef->{'SensorName'} ;
						my $SensorUnit = $SensorDetailsHashRef->{'SensorUnit'} ;
						$CSVFileStr .= ", $SensorName ($SensorUnit)" ;
					}

					$CSVFileStr .= "\n" ;

					my $CurrNumSamples = 0 ;
					my $IntermediateKeyPress ;
					do {

						$SampleStartTime = [gettimeofday];
						do {
							$GetResponse0 = $UA->get ($CurrPage) ;
						} while !($GetResponse0->is_success) ;
						$DevStatusJSON = $GetResponse0->decoded_content ;
						my $JSONText = $JSON->decode ($DevStatusJSON) ;
						my $CurrTime = [gettimeofday];
						my $Elapsed = tv_interval($SampleStartTime, $CurrTime);
						my $NumWholeSeconds = int($Elapsed);
						my $FictRec = 0;
						my $CurrCSVEntry ;
						do {
							$CurrNumSamples ++ ;
							$CurrCSVEntry = sprintf ("%d", $CurrNumSamples) ;

							for my $TmpIdx (0 .. scalar @TrackedIndicesArray - 1) {
								my $JSONIdx = $TrackedIndicesArray[$TmpIdx] ;
								my $SensorDetailsHashRef = $JSONText->[$JSONIdx];
								my $SensorValue = $SensorDetailsHashRef->{'SensorValue'};
								my $RetryNumber = 0 ;
								while (not defined $SensorValue) {	
									do {
										$GetResponse0 = $UA->get ($CurrPage) ;
									} while !($GetResponse0->is_success) ;
									$DevStatusJSON = $GetResponse0->decoded_content ;
									$JSONText = $JSON->decode ($DevStatusJSON) ;
									$SensorDetailsHashRef = $JSONText->[$TmpIdx];
									$SensorValue = $SensorDetailsHashRef->{'SensorValue'};
									$RetryNumber ++ ;
									if ($RetryNumber > 50) {
										printf "\nMore than 50 retries without getting proper value.." ;
										print Dumper $JSONText ;
										$TmpKey = <>;
									}
								}
								$CurrCSVEntry .= sprintf (", %.02f",$SensorValue) ;
							}
							$FictRec ++;
							printf "\rEnqueueing to CSV File : %s\t\t", $CurrCSVEntry ;
							$CurrCSVEntry .= "\n" ;
							$CSVFileStr .= $CurrCSVEntry ;
						} while ($FictRec < $NumWholeSeconds);
						$CurrTime = [gettimeofday] ;
						$Elapsed = tv_interval ($SampleStartTime, $CurrTime) ;
						my $SleepInterval = 1.00 - ($Elapsed - int($Elapsed)) ;
						Time::HiRes::sleep ($SleepInterval) ;
						$IntermediateKeyPress = ReadKey(-1);
						if (not defined $IntermediateKeyPress) {
							$IntermediateKeyPress = 'c' ;
						}
					} while (!($IntermediateKeyPress eq "q" || $IntermediateKeyPress eq "Q")) ;

					open ($CSV_FileHandle, ">$CSV_FileName") or die "Can't open $CSV_FileName for writing\nRaw CSV Data: $CSVFileStr" ;
					printf $CSV_FileHandle "$CSVFileStr" ;
					close ($CSV_FileHandle) ;
					$WaitForInputs = 0;
					ReadMode (0);


				} elsif ($KeyPress eq "Q" || $KeyPress eq "q") {

					$WaitForInputs = 0 ;

				}

			}

		}

	} else {

		exit(0) ;

	}

}

sub ClearScreen {

	system $^O eq 'MSWin32' ? 'cls' : 'clear';

}

END { 
	ReadMode 0 ;
}
